package yu.com.time

import yu.com.time.calclator.TimestampCalculator
import yu.com.time.unit.DateTimeUnit
import java.sql.Time
import java.sql.Timestamp
import java.text.ParseException
import java.text.SimpleDateFormat
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.*


/**
 * 对java.util.Date日期时间进行拓展
 * created zpf on 2018/10/23 0023
 */

/**
 * java.util.Date日期时间工具类
 * created zpf on 2018/10/23 0023
 */
object DateTimes {

    /**标准日期部分:yyyy-MM-dd*/
    const val DATE = "yyyy-MM-dd"

    /**标准时间部分:HH:mm*/
    const val TIME = "HH:mm:ss"

    /**标准日期时间:yyyy-MM-dd HH:mm:ss*/
    const val DATETIME = "yyyy-MM-dd HH:mm:ss"

    /**MySql 标准精确到毫秒:yyyy-MM-dd HH:mm:ss.SSS*/
    const val MILLI = "yyyy-MM-dd HH:mm:ss.SSS"

    /**年月:yyyy-MM*/
    const val MONTH = "yyyy-MM"

    /**年月日时分:yyyy-MM-dd HH:mm*/
    const val MINUTE = "yyyy-MM-dd HH:mm"

    /**格式数组*/
    val formats: List<String> = arrayOf(DATE, TIME, DATETIME, MILLI, MONTH, MINUTE).sortedBy { -it.length }

    /**
     * 解析的时间字符串
     * @param timeStr 时间字符串
     * @param pattern 解析格式
     */
    fun parse(timeStr: String, pattern: String): Timestamp {
        return SimpleDateFormat(pattern).parse(timeStr).toTimestamp()
    }

    /**
     * 获取时间字符串的格式
     * @param timeStr 时间字符串
     */
    fun getPattern(timeStr: String): String {
        val patten = formats.find {
            try {
                parse(timeStr, it)
                true
            } catch (e: ParseException) {
                false
            }
        }
        return patten ?: throw ParseException("未找到与“${timeStr}”匹配的日期时间解析格式。", 0)
    }

    /**
     * 格式化时间
     * @param dateTime 时间
     * @param pattern 格式
     */
    fun format(dateTime: Date, pattern: String): String {
        return SimpleDateFormat(pattern).format(dateTime)
    }
}


/**日期时间字符串:yyyy-MM-dd HH:mm:ss*/
val java.util.Date.str get() = this.format(DateTimes.DATETIME)

/**日期字符串:yyyy-MM-dd*/
val java.util.Date.dateStr get() = this.format(DateTimes.DATE)

/**日期字符串:yyyy-MM-dd*/
val java.util.Date.timeStr get() = this.format(DateTimes.DATE)

/**毫秒字符串mysql标准(yyyy-MM-dd HH:mm:ss.SSS)*/
val java.util.Date.milliStr get() = this.format("yyyy-MM-dd HH:mm:ss.SSS")

/**
 * 将日期时间格式化
 * @param format 指定格式
 */
fun java.util.Date.format(format: String = "yyyy-MM-dd HH:mm:ss"): String = DateTimes.format(this, format)

/**
 * 转换到jdk1.8的日期时间
 */
//此处为了兼容java.sql.Date ,而使用的 Instant.ofEpochMilli 而非使用 toInstant
fun java.util.Date.toLocalDateTime(): LocalDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault())

/**
 * date转换为时间戳
 */
fun java.util.Date.toTimestamp(): Timestamp = java.sql.Timestamp(this.time)

/**
 * date转换为纯日期
 */
fun java.util.Date.toDate(): java.sql.Date = toLocalDateTime().toLocalDate().toDate()

/**
 * date转化为时间
 */
fun java.util.Date.toTime(): Time = java.sql.Time(this.time)

/**
 * 设置日期部分
 * @param date 要设置的日期部分
 */
fun java.util.Date.withDate(date: java.sql.Date): Timestamp = this.toLocalDateTime().withDate(date.toLocalDate()).toTimestamp()

/**
 * 设置时间部分
 * @param time 要设置的时间部分
 */
fun java.util.Date.withTime(time: Time): Timestamp = this.toLocalDateTime().withTime(time.toLocalTime()).toTimestamp()

/**
 * 设置时间部分
 * @param year 设置小时部分,默认置为0，如果填写null则不改变
 * @param month 设置分钟部分,默认置为1，如果填写null则不改变
 * @param day 设置秒部分,默认置为1，如果填写null则不改变
 */
fun java.util.Date.withDate(year: Int? = 0, month: Int? = 1, day: Int? = 1): Timestamp {
    return toLocalDateTime().withDate(year, month, day).toTimestamp()
}

/**
 * 设置时间部分
 * @param hour 设置小时部分,默认置为0，如果填写null则不改变
 * @param minute 设置分钟部分,默认置为0，如果填写null则不改变
 * @param second 设置秒部分,默认置为0，如果填写null则不改变
 * @param milli 设置毫秒部分,默认置为0，如果填写null则不改变
 */
fun java.util.Date.withTime(hour: Int? = 0, minute: Int? = 0, second: Int? = 0, milli: Int? = 0): Timestamp {
    return toLocalDateTime().withTime(hour, minute, second, milli?.let { it * 1000 * 1000 }).toTimestamp()
}


/**年份计算*/
val java.util.Date.cYear get() = TimestampCalculator(this, DateTimeUnit.YEAR)

/**月份计算*/
val java.util.Date.cMonth get() = TimestampCalculator(this, DateTimeUnit.MONTH)

/**星期计算*/
val java.util.Date.cWeek get() = TimestampCalculator(this, DateTimeUnit.WEEK)

/**天数计算*/
val java.util.Date.cDay get() = TimestampCalculator(this, DateTimeUnit.DAY)

/**小时计算*/
val java.util.Date.cHour get() = TimestampCalculator(this, DateTimeUnit.HOUR)

/**分钟计算*/
val java.util.Date.cMinute get() = TimestampCalculator(this, DateTimeUnit.MINUTE)

/**秒钟计算*/
val java.util.Date.cSecond get() = TimestampCalculator(this, DateTimeUnit.SECOND)

/**毫秒计算*/
val java.util.Date.cMilli get() = TimestampCalculator(this, DateTimeUnit.MILLI)